﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using BookSleeve;
using RedisDemos.Extensions;

namespace RedisDemos.Scenarios
{
    public class ActiveUsers : Scenario
    {
        protected override async Task Perform(RedisConnection conn)
        {
            var now = DateTime.Now;

            await Task.WhenAll(RegisterUser(conn, new UserModel { UserName = "tank-1" }),
                               RegisterUser(conn, new UserModel { UserName = "mario.rossi" }),
                               RegisterUser(conn, new UserModel { UserName = "mario.bianchi" }),
                               RegisterUser(conn, new UserModel { UserName = "foo" }));

            await UserVisitPage(conn, "foo", url: "/mail/inbox", when: now);
            await UserVisitPage(conn, "tank-1", url: "/mail/inbox", when: now.AddDays(-1));
            await UserVisitPage(conn, "mario.rossi", url: "/mail/inbox", when: now.AddDays(-7));
            await UserVisitPage(conn, "mario.bianchi", url: "/mail/inbox", when: now.AddMonths(-2));

            await DailyVisitPage(conn, url: "/mail/inbox", today: now);
            await MonthlyVisitPage(conn, url: "/mail/inbox", today: now);
        }

        private async Task UserVisitPage(RedisConnection conn, String username, String url, DateTime when)
        {
            // GET key
            var userId = await conn.Strings.Get(Db, String.Format("username:{0}", username));

            // SETBIT key offset value 
            await conn.Strings.SetBit(Db, String.Format("page:{0}:{1}", url, when.ToString("yyyyMMdd")), userId.AsInt64(), true);
        }

        private async Task DailyVisitPage(RedisConnection conn, String url, DateTime today)
        {
            // BITCOUNT key [start] [end] 
            var tot = await conn.Strings.CountSetBits(Db, String.Format("page:{0}:{1}", url, today.ToString("yyyyMMdd")));
            "***** Daily: {0}".LogInfo(tot);
        }

        private async Task MonthlyVisitPage(RedisConnection conn, String url, DateTime today)
        {
            var monthlyKeys = today.Days()
                               .Select(d => String.Format("page:{0}:{1}", url, d.ToString("yyyyMMdd")))
                               .ToArray();

            // BITOP operation destkey srckey1 srckey2 srckey3 ... srckeyN
            await conn.Strings.BitwiseOr(Db, String.Format("page:{0}:monthly", url), monthlyKeys);

            // BITCOUNT key [start] [end] 
            var tot = await conn.Strings.CountSetBits(Db, String.Format("page:{0}:monthly", url));
            "***** Monthly: {0}".LogInfo(tot);            
        }

        private async Task RegisterUser(RedisConnection conn, UserModel model)
        {
            // SADD key member [member ...] 
            var wasAdded = await conn.Sets.Add(Db, "username:all", model.UserName);
            if (wasAdded == false)
                throw new InvalidOperationException("User name already exists.");

            // INCR key 
            var newId = await conn.Strings.Increment(Db, "users:nextid");            

            // SET key value 
            // HMSET key field value [field value ...] 
            await Task.WhenAll(conn.Strings.Set(Db, String.Format("username:{0}", model.UserName), newId),
                               conn.Hashes.Set(Db, String.Format("user:{0}", newId), model.AsHash()));
        }
    }
}
